package cn.newzai.parser.proto.result.generate

import cn.newzai.parser.proto.result._



/**
 * Created with IntelliJ IDEA.
 * User: chenxiaohong
 * Date: 13-6-4
 * Time: 下午2:32
 * To change this template use File | Settings | File Templates.
 */

trait MessageGenerateCSharpCode extends MessageGenerate {
  this : Message =>
  override def generate_code(gen_type: GenerateCodeType.Value): String = {
    if ( gen_type == GenerateCodeType.CSharpCode ){
      val baseName = if ( base != null){
        base.data_type match {
          case MessageType(name) => name
          case _ => ""

        }
      }else{
        "Notify"
      }

      val fromBase = if ( base != null) {
          "base.fromMessage( msg.Base );"
      } else{
        ""
      }

      val toBase = if ( base != null ){
        s"""
          |${Message.package_name}.${baseName}.Builder baseBuilder = ${Message.package_name}.${baseName}.CreateBuilder();
          |base.toMessage(ref baseBuilder );
          |builder.Base = baseBuilder.Build();
        """.stripMargin
      }else{
        ""
      }
      println(s"start gen charp code for ${name}")
      s"""
        |public partial class ${name} : ${baseName}
        |{
        | ${ fields.map( _.generate_code(gen_type)).mkString("\n")}
        |
        | public void fromMessage( ${Message.package_name}.${name} msg )
        | {
        |   ${fromBase}
        |   ${ fields.map( _.generate_code(GenerateCodeType.Protobuf2CSharp)).mkString("\n")}
        | }
        | public void toMessage( ref ${Message.package_name}.${name}.Builder builder)
        | {
        |   ${toBase}
        |   ${ fields.map( _.generate_code(GenerateCodeType.CSharp2Protobuf)).mkString("\n")}
        | }
        | public object Clone()
        | {
        |   ${name} c = new ${name}();
        |   ${fields.map(_.generate_code(GenerateCodeType.CSharpClone)).mkString("\n")}
        |   return c as object;
        | }
        |}
      """.stripMargin
    }else{
      super.generate_code(gen_type)
    }
  }
}


trait FieldGenerateCSharpCode extends FieldGenerate{
  this : Field =>
  override def generate_code_basic_type_required(gen_type: GenerateCodeType.Value, typeName: String): String = {

    if ( gen_type == GenerateCodeType.CSharpCode){
      val type_ = ProtobufType(typeName)
      val csharp_type = ProtobufType.csharp_type_map(type_)
      val default = ProtobufType.csharp_type_default(type_)
      s"""
        |private ${csharp_type} ${toFieldName} = ${default};
        |
        |public ${csharp_type} ${toMethodName}
        |{
        | get { return ${toFieldName};}
        | set
        | {
        |   if ( value != ${toFieldName} )
        |   {
        |     ${toFieldName} = value;
        |     OnPropertyChanged("${toMethodName}");
        |   }
        | }
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_required(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_optional(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      val type_ = ProtobufType(typeName)
      val csharp_type = ProtobufType.csharp_type_map(type_)
      val default = ProtobufType.csharp_type_default(type_)
      s"""
        |private ${csharp_type} ${toFieldName} = ${default};
        |
        |public ${csharp_type} ${toMethodName}
        |{
        | get { return ${toFieldName};}
        | set
        | {
        |   if ( value != ${toFieldName} )
        |   {
        |     ${toFieldName} = value;
        |     OnPropertyChanged("${toMethodName}");
        |   }
        | }
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_repeated(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      val type_ = ProtobufType(typeName)
      val csharp_type = ProtobufType.csharp_type_map(type_)
      s"""
        |private ObservableCollection<${csharp_type}> ${toFieldName} = new ObservableCollection<${csharp_type}>();
        |public ObservableCollection<${csharp_type}> ${toMethodName}
        |{
        | get { return ${toFieldName}; }
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_required(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      val csharp_type = s"${Message.package_name}.${typeName}"

      val default     = s"${Message.package_name}.${typeName}.${Enum.getEnum(typeName).default}"
      val enum = Enum.getEnum(typeName)

      def eachEnumValue( value : String) ={
        s"""
          |public bool ${toMethodName}${value}
          |{
          | get{ return ${toMethodName} == ${Message.package_name}.${typeName}.${value}; }
          | set{ if (value ){ ${toMethodName} = ${Message.package_name}.${typeName}.${value};} }
          |}
        """.stripMargin
      }
      s"""
        |private ${csharp_type} ${toFieldName} =  ${default};
        |
        |public ${csharp_type} ${toMethodName}
        |{
        | get { return ${toFieldName};}
        | set
        | {
        |   if ( value != ${toFieldName} )
        |   {
        |     ${toFieldName} = value;
        |     OnPropertyChanged("${toMethodName}");
        |${ enum.values.map( v => s"""OnPropertyChanged("${toMethodName}${v._1}");""").mkString("\n")}
        |   }
        | }
        |}
        |${enum.values.map( v => eachEnumValue(v._1)).mkString("\n")}
      """.stripMargin
    }else{
      super.generate_code_enum_type_required(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_optional(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
        generate_code_enum_type_required(gen_type, typeName)
    }else{
      super.generate_code_enum_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_repeated(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      val csharp_type = s"${Message.package_name}.${typeName}"
      s"""
        |private ObservableCollection<${csharp_type}> ${toFieldName} = new ObservableCollection<${csharp_type}>();
        |public ObservableCollection<${csharp_type}> ${toMethodName}
        |{
        | get { return ${toFieldName}; }
        |}
      """.stripMargin
    }else{
      super.generate_code_enum_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_message_type_required(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      s"""
        |private ${typeName} ${toFieldName} = new ${typeName}();
        |
        |public ${typeName} ${toMethodName}
        |{
        | get { return ${toFieldName}; }
        |
        |
        |
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_required(gen_type, typeName)
    }
  }

  override def generate_code_message_type_optional(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      s"""
        |private ${typeName} ${toFieldName} = new ${typeName}();
        |private bool        ${toFieldName}_enable = false;
        |
        |public ${typeName} ${toMethodName}
        |{
        | get { return ${toFieldName}; }
        |}
        |public bool ${toMethodName}Enable
        |{
        | get { return ${toFieldName}_enable; }
        | set
        | {
        |   if( ${toFieldName}_enable != value )
        |   {
        |     ${toFieldName}_enable = value;
        |     OnPropertyChanged("${toMethodName}Enable");
        |   }
        | }
        |}
        |
      """.stripMargin
    }else{
      super.generate_code_message_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_message_type_repeated(gen_type: GenerateCodeType.Value, typeName: String): String = {
    if ( gen_type == GenerateCodeType.CSharpCode){
      val csharp_type = typeName
      s"""
        |private ObservableCollection<${csharp_type}> ${toFieldName} = new ObservableCollection<${csharp_type}>();
        |public ObservableCollection<${csharp_type}> ${toMethodName}
        |{
        | get { return ${toFieldName}; }
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_repeated(gen_type, typeName)
    }
  }
}


trait FieldGenerateProtobuf2CSharp extends FieldGenerate {
  this : Field =>
  import GenerateCodeType._
  override def generate_code_basic_type_required(gen_type: Value, typeName: String): String = {
    val msgValue = ProtobufType(typeName) match {
      case ProtobufType.bytes =>  s"""msg.${toMethodName}.ToString(Encoding.GetEncoding("GB2312"))"""
      case _ => s"msg.${toMethodName}"
    }
    if ( gen_type == Protobuf2CSharp){
      s"""
        |if ( msg.Has${toMethodName} )
        |{
        |   ${toMethodName} = ${msgValue} ;
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_required(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_basic_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      val msgValue = ProtobufType(typeName) match {
        case ProtobufType.bytes =>  s"""msg.Get${toMethodName}(i).ToString(Encoding.GetEncoding("GB2312"))"""
        case _ => s"msg.Get${toMethodName}(i)"
      }
      s"""
        |if ( msg.HasInclude${toMethodName} && msg.Include${toMethodName} )
        |{
        | ${toMethodName}.Clear();
        | for( int i = 0 ; i < msg.${toMethodName}Count; i ++ )
        | {
        |   ${toMethodName}.Add( ${msgValue} );
        | }
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_enum_type_required(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_enum_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      generate_code_basic_type_repeated(gen_type,typeName)
    }else{
      super.generate_code_enum_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_message_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
     s"""
        |if ( msg.Has${toMethodName} )
        |{
        | ${toMethodName}.fromMessage( msg.${toMethodName} );
        |}
        |
      """.stripMargin
    }else{
      super.generate_code_message_type_required(gen_type, typeName)
    }
  }

  override def generate_code_message_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      s"""
        |if ( msg.Has${toMethodName} )
        |{
        | ${toMethodName}Enable = true;
        | ${toMethodName}.fromMessage( msg.${toMethodName} );
        |}else
        |{
        |   ${toMethodName}Enable = false;
        |}
        |
      """.stripMargin
    }else{
      super.generate_code_message_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_message_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == Protobuf2CSharp){
      s"""
        |if ( msg.HasInclude${toMethodName} && msg.Include${toMethodName} )
        |{
        | ${toMethodName}.Clear();
        | for( int i = 0 ; i < msg.${toMethodName}Count ; i ++ )
        | {
        |   ${typeName} value = new ${typeName}();
        |   value.fromMessage(msg.Get${toMethodName}(i));
        |   ${toMethodName}.Add(value);
        | }
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_repeated(gen_type, typeName)
    }
  }
}

trait FieldGenerateCSharp2Protobuf extends FieldGenerate {
  this : Field =>
  import GenerateCodeType._

  override def generate_code_basic_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      val toMsgValue = ProtobufType(typeName) match {
        case ProtobufType.bytes => s"""Google.ProtocolBuffers.ByteString.CopyFrom (${toMethodName},Encoding.GetEncoding("GB2312")) """
        case _ => toMethodName
      }
        s"builder.${toMethodName} = ${toMsgValue};"
    }else{
      super.generate_code_basic_type_required(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_basic_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      val toMsgValue = ProtobufType(typeName) match {
        case ProtobufType.bytes => s"""Google.ProtocolBuffers.ByteString.CopyFrom (v,Encoding.GetEncoding("GB2312")) """
        case _ => "v"
      }
      s"""
        |builder.Include${toMethodName} = true;
        |foreach( var v in ${toMethodName} )
        |{
        |   builder.Add${toMethodName}(${toMsgValue});
        |}

      """.stripMargin
    }else{
      super.generate_code_basic_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_enum_type_required(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      generate_code_basic_type_required(gen_type,typeName)
    }else{
      super.generate_code_enum_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      generate_code_basic_type_repeated(gen_type,typeName)
    }else{
      super.generate_code_enum_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_message_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      s"""
        |${Message.package_name}.${typeName}.Builder  ${name}_builder =  ${Message.package_name}.${typeName}.CreateBuilder();
        |${toMethodName}.toMessage( ref ${name}_builder );
        |builder.${toMethodName} = ${name}_builder.Build();
      """.stripMargin
    }else{
      super.generate_code_message_type_required(gen_type, typeName)
    }
  }

  override def generate_code_message_type_optional(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      s"""
        |if ( ${toMethodName}Enable )
        |{
        | ${Message.package_name}.${typeName}.Builder  ${name}_builder =  ${Message.package_name}.${typeName}.CreateBuilder();
        | ${toMethodName}.toMessage( ref ${name}_builder );
        | builder.${toMethodName} = ${name}_builder.Build();
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_message_type_repeated(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharp2Protobuf){
      s"""
        |builder.Include${toMethodName} = true;
        |foreach( var v in ${toMethodName} )
        |{
        | ${Message.package_name}.${typeName}.Builder  _builder =  ${Message.package_name}.${typeName}.CreateBuilder();
        | v.toMessage( ref _builder );
        | builder.Add${toMethodName}( _builder.Build() );
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_repeated(gen_type, typeName)
    }
  }
}

trait FieldGenerateCSharpClone extends  FieldGenerate
{
  this : Field =>
  import GenerateCodeType._

  override def generate_code_basic_type_required(gen_type: Value, typeName: String): String = {
    if ( gen_type == CSharpClone){
      s"""
        |c.${toMethodName} = ${toMethodName};
      """.stripMargin
    }else{
      super.generate_code_basic_type_required(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_optional(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |c.${toMethodName} = ${toMethodName};
      """.stripMargin
    }else{
      super.generate_code_basic_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_basic_type_repeated(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |foreach( var e in ${toMethodName} )
        |{
        | c.${toMethodName}.Add(e);
        |}
      """.stripMargin
    }else{
      super.generate_code_basic_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_required(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |c.${toMethodName} = ${toMethodName};
      """.stripMargin
    }else{
      super.generate_code_enum_type_required(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_optional(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |c.${toMethodName} = ${toMethodName};
      """.stripMargin
    }else{
      super.generate_code_enum_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_enum_type_repeated(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |foreach( var e in ${toMethodName} )
        |{
        | c.${toMethodName}.Add(e);
        |}
      """.stripMargin
    }else{
      super.generate_code_enum_type_repeated(gen_type, typeName)
    }
  }

  override def generate_code_message_type_required(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |if ( ${toMethodName} != null)
        |{
        | c.${toFieldName} = (${typeName})${toMethodName}.Clone();
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_required(gen_type, typeName)
    }
  }

  override def generate_code_message_type_optional(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |c.${toMethodName}Enable = ${toMethodName}Enable;
        |if ( ${toMethodName}Enable )
        |{
        |  c.${toFieldName} = (${typeName})${toMethodName}.Clone();
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_optional(gen_type, typeName)
    }
  }

  override def generate_code_message_type_repeated(gen_type: Value, typeName: String): String = {
    if (gen_type == CSharpClone){
      s"""
        |foreach( var e in ${toMethodName} )
        |{
        | c.${toMethodName}.Add((${typeName})e.Clone());
        |}
      """.stripMargin
    }else{
      super.generate_code_message_type_repeated(gen_type, typeName)
    }
  }
}